home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tar.gnu / sprite / extract.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-29  |  21.3 KB  |  819 lines

  1. /* Extract files from a tar archive.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * Extract files from a tar archive.
  22.  *
  23.  * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  24.  *
  25.  * @(#) extract.c 1.32 87/11/11 - gnu
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <sys/param.h>
  33.  
  34. #ifdef BSD42
  35. #include <sys/file.h>
  36. #endif
  37.  
  38. #ifdef USG
  39. #include <fcntl.h>
  40. #endif
  41.  
  42. #ifdef    MSDOS
  43. #include <fcntl.h>
  44. #endif    /* MSDOS */
  45.  
  46. /*
  47.  * Some people don't have a #define for these.
  48.  */
  49. #ifndef    O_BINARY
  50. #define    O_BINARY    0
  51. #endif
  52. #ifndef O_NDELAY
  53. #define    O_NDELAY    0
  54. #endif
  55.  
  56. #ifdef NO_OPEN3
  57. /* We need the #define's even though we don't use them. */
  58. #include "open3.h"
  59. #endif
  60.  
  61. #ifdef EMUL_OPEN3
  62. /* Simulated 3-argument open for systems that don't have it */
  63. #include "open3.h"
  64. #endif
  65.  
  66. extern int errno;            /* From libc.a */
  67. extern time_t time();            /* From libc.a */
  68. extern char *index();            /* From libc.a or port.c */
  69.  
  70. #include "tar.h"
  71. #include "port.h"
  72.  
  73. extern FILE *msg_file;
  74.  
  75. extern union record *head;        /* Points to current tape header */
  76. extern struct stat hstat;        /* Stat struct corresponding */
  77. extern int head_standard;        /* Tape header is in ANSI format */
  78.  
  79. extern char *save_name;
  80. extern long save_totsize;
  81. extern long save_sizeleft;
  82.  
  83. extern void print_header();
  84. extern void skip_file();
  85. extern void skip_extended_headers();
  86. extern void pr_mkdir();
  87.  
  88. int make_dirs();            /* Makes required directories */
  89.  
  90. static time_t now = 0;            /* Current time */
  91. static we_are_root = 0;            /* True if our effective uid == 0 */
  92. static int notumask = ~0;        /* Masks out bits user doesn't want */
  93.  
  94. /*
  95.  * "Scratch" space to store the information about a sparse file before
  96.  * writing the info into the header or extended header
  97.  */
  98. /*struct sp_array    *sparsearray;*/
  99.  
  100. /* number of elts storable in the sparsearray */
  101. /*int    sp_array_size = 10;*/
  102.  
  103. /*
  104.  * Set up to extract files.
  105.  */
  106. extr_init()
  107. {
  108.     int ourmask;
  109.  
  110.     now = time((time_t *)0);
  111.     if (geteuid() == 0)
  112.         we_are_root = 1;
  113.  
  114.     /*
  115.      * We need to know our umask.  But if f_use_protection is set,
  116.      * leave our kernel umask at 0, and our "notumask" at ~0.
  117.      */
  118.     ourmask = umask(0);        /* Read it */
  119.     if (!f_use_protection) {
  120.         (void) umask (ourmask);    /* Set it back how it was */
  121.         notumask = ~ourmask;    /* Make umask override permissions */
  122.     }
  123. }
  124.  
  125.  
  126. /*
  127.  * Extract a file from the archive.
  128.  */
  129. void
  130. extract_archive()
  131. {
  132.     register char *data;
  133.     int fd, check, namelen, written, openflag;
  134.     long size;
  135.     time_t acc_upd_times[2];
  136.     register int skipcrud;
  137.     register int i;
  138.     int sparse_ind = 0;
  139.     union record *exhdr;    
  140.     int end_nulls;
  141.  
  142.     sp_array_size = 10;
  143.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  144.  
  145.     if(f_confirm && !confirm("extract",current_filename)) {
  146.         if (gnu_extended_header(head))
  147.             skip_extended_headers();
  148.         skip_file((long)hstat.st_size);
  149.         return;
  150.     }
  151.  
  152.     /* Print the record from 'head' and 'hstat' */
  153.     if (f_verbose)
  154.         print_header();
  155.  
  156.     /*
  157.      * Check for fully specified pathnames and other atrocities.
  158.      *
  159.      * Note, we can't just make a pointer to the new file name,
  160.      * since saverec() might move the header and adjust "head".
  161.      * We have to start from "head" every time we want to touch
  162.      * the header record.
  163.      */
  164.     skipcrud = 0;
  165.     while (!f_absolute_paths && '/' == current_filename[skipcrud]) {
  166.         static int warned_once = 0;
  167.  
  168.         skipcrud++;    /* Force relative path */
  169.         if (!warned_once++) {
  170.             msg("Removing leading / from absolute path names in the archive.");
  171.         }
  172.     }
  173.  
  174.     sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
  175.     switch (head->header.linkflag) {
  176.  
  177.     default:
  178.         msg("Unknown file type '%c' for %s, extracted as normal file",
  179.             head->header.linkflag, skipcrud+current_filename);
  180.         /* FALL THRU */
  181.  
  182.     /* 
  183.      * JK - What we want to do if the file is sparse is loop through
  184.      * the array of sparse structures in the header and read in
  185.      * and translate the character strings representing  1) the offset
  186.      * at which to write and 2) how many bytes to write into numbers,
  187.      * which we store into the scratch array, "sparsearray".  This
  188.      * array makes our life easier the same way it did in creating
  189.      * the tar file that had to deal with a sparse file.
  190.      *
  191.      * After we read in the first five (at most) sparse structures,
  192.      * we check to see if the file has an extended header, i.e., 
  193.      * if more sparse structures are needed to describe the contents
  194.      * of the new file.  If so, we read in the extended headers
  195.      * and continue to store their contents into the sparsearray.
  196.      */
  197.     case LF_SPARSE:
  198.         for (i = 0; i < SPARSE_IN_HDR; i++) {
  199.             if (!head->header.sp[i].numbytes)
  200.                 break;
  201.             sparsearray[i].offset = 
  202.                 from_oct(1+12, head->header.sp[i].offset);
  203.             sparsearray[i].numbytes = 
  204.                 from_oct(1+12, head->header.sp[i].numbytes);
  205.         }
  206.  
  207. /*        end_nulls = from_oct(1+12, head->header.ending_blanks);*/
  208.  
  209.         if (gnu_extended_header(head) &&
  210.             (head->header.isextended & XH_SPARSE_FILE)) {
  211.             /* read in the list of extended headers
  212.                and translate them into the sparsearray 
  213.                as before */
  214.  
  215.             static int ind = SPARSE_IN_HDR;
  216.  
  217.             for (;;) {
  218.  
  219.                 exhdr = findrec();
  220.                 for (i = 0; i < SPARSE_EXT_HDR; i++) {
  221.  
  222.                     if (i+ind > sp_array_size-1) {
  223.                     /*
  224.                      * realloc the scratch area
  225.                      * since we've run out of room --
  226.                      */
  227.                         sparsearray = (struct sp_array *) 
  228.                                 realloc(sparsearray,
  229.                                 2 * sp_array_size * (sizeof(struct sp_array)));
  230.                         sp_array_size *= 2;
  231.                     }
  232.                     if (!exhdr->ext_hdr.xh_sp[i].numbytes)
  233.                         break;
  234.                     sparsearray[i+ind].offset = 
  235.                         from_oct(1+12, exhdr->ext_hdr.xh_sp[i].offset);
  236.                     sparsearray[i+ind].numbytes = 
  237.                         from_oct(1+12, exhdr->ext_hdr.xh_sp[i].numbytes);
  238.                 }
  239.                 if (!exhdr->ext_hdr.xh_isextended) 
  240.                     break;
  241.                 else {
  242.                     ind += SPARSE_EXT_HDR;
  243.                     userec(exhdr);
  244.                 }
  245.             }
  246.             userec(exhdr);
  247.         }
  248.  
  249.         /* FALL THRU */
  250.     case LF_OLDNORMAL:
  251.     case LF_NORMAL:
  252.     case LF_CONTIG:
  253.  
  254.         /*
  255.          * Appears to be a file.
  256.          * See if it's really a directory.
  257.          */
  258.         namelen = strlen(skipcrud+current_filename)-1;
  259.         if (current_filename[skipcrud+namelen] == '/')
  260.             goto really_dir;
  261.  
  262.         /* FIXME, deal with protection issues */
  263.     again_file:
  264.         openflag = (f_keep?
  265. #ifdef sprite
  266.             /*
  267.              * Currently, a bug in the sprite file system makes
  268.              * opening regular files with O_NDELAY a bad idea.
  269.              * Writes fail with EWOULDBLOCK when local cache
  270.              * fills.
  271.              */
  272.             O_BINARY|O_WRONLY|O_CREAT|O_EXCL:
  273.             O_BINARY|O_WRONLY|O_CREAT|O_TRUNC)
  274. #else
  275.             O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
  276.             O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
  277. #endif
  278.             | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);            
  279.             /*
  280.              * JK - The last | is a kludge to solve the problem
  281.              * the O_APPEND flag  causes with files we are
  282.              * trying to make sparse:  when a file is opened
  283.              * with O_APPEND, it writes  to the last place
  284.              * that something was written, thereby ignoring
  285.              * any lseeks that we have done.  We add this
  286.              * extra condition to make it able to lseek when
  287.              * a file is sparse, i.e., we don't open the new
  288.              * file with this flag.  (Grump -- this bug caused
  289.              * me to waste a good deal of time, I might add)
  290.                */
  291.  
  292.         if(f_exstdout) {
  293.             fd = 1;
  294.             goto extract_file;
  295.         }
  296. #ifdef O_CTG
  297.         /*
  298.          * Contiguous files (on the Masscomp) have to specify
  299.          * the size in the open call that creates them.
  300.          */
  301.         if (head->header.linkflag == LF_CONTIG)
  302.             fd = open(skipcrud+current_filename, openflag | O_CTG,
  303.                 hstat.st_mode, hstat.st_size);
  304.         else
  305. #endif
  306.         {
  307. #ifdef NO_OPEN3
  308.             /*
  309.              * On raw V7 we won't let them specify -k (f_keep), but
  310.              * we just bull ahead and create the files.
  311.              */
  312.             fd = creat(skipcrud+current_filename, hstat.st_mode);
  313. #else
  314.             /*
  315.              * With 3-arg open(), we can do this up right.
  316.              */
  317.             fd = open(skipcrud+current_filename, openflag, hstat.st_mode);
  318. #endif
  319.         }
  320.  
  321.         if (fd < 0) {
  322.             if (make_dirs(skipcrud+current_filename))
  323.                 goto again_file;
  324.             msg_perror("Could not create file %s",skipcrud+current_filename);
  325.             if (gnu_extended_header(head))
  326.                 skip_extended_headers();
  327.             skip_file((long)hstat.st_size);
  328.             goto quit;
  329.         }
  330.  
  331.     extract_file:
  332.         if (head->header.linkflag == LF_SPARSE) {
  333.             char    *name;
  334.             int    namelen;
  335.  
  336.             /*
  337.              * Kludge alert.  NAME is assigned to header.name
  338.              * because during the extraction, the space that
  339.              * contains the header will get scribbled on, and
  340.              * the name will get munged, so any error messages
  341.              * that happen to contain the filename will look
  342.              * REAL interesting unless we do this.
  343.              * (XXX or at least it used to be like this, before 
  344.              * get_names() was put in. -mdk)
  345.              */
  346.             namelen = strlen(skipcrud+current_filename);
  347.             name = (char *) malloc((sizeof(char)) * namelen);
  348.             bcopy(skipcrud+current_filename, name, namelen);
  349.             size = hstat.st_size;
  350.             extract_sparse_file(fd, &size, hstat.st_size,
  351.                          name);
  352.         }            
  353.         else         
  354.           for (size = hstat.st_size;
  355.                size > 0;
  356.                size -= written) {
  357.             if(f_multivol) {
  358.                 save_name=current_filename;
  359.                 save_totsize=hstat.st_size;
  360.                 save_sizeleft=size;
  361.             }
  362.             
  363.             /*
  364.              * Locate data, determine max length
  365.              * writeable, write it, record that
  366.              * we have used the data, then check
  367.              * if the write worked.
  368.              */
  369.             data = findrec()->charptr;
  370.             if (data == NULL) {    /* Check it... */
  371.                 msg("Unexpected EOF on archive file");
  372.                 break;
  373.             }
  374.             /*
  375.              * JK - If the file is sparse, use the sparsearray
  376.              * that we created before to lseek into the new
  377.              * file the proper amount, and to see how many
  378.              * bytes we want to write at that position.
  379.              */
  380. /*            if (head->header.linkflag == LF_SPARSE) {
  381.                 off_t pos;
  382.                 
  383.                 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
  384.                 printf("%d at %d\n", (int) pos, sparse_ind);
  385.                 written = sparsearray[sparse_ind++].numbytes;
  386.             } else*/
  387.             written = endofrecs()->charptr - data;
  388.             if (written > size)
  389.                 written = size;
  390.             errno = 0;
  391.             check = write(fd, data, written);
  392.             /*
  393.              * The following is in violation of strict
  394.              * typing, since the arg to userec
  395.              * should be a struct rec *.  FIXME.
  396.              */
  397.             userec((union record *)(data + written - 1));
  398.             if (check == written) continue;
  399.             /*
  400.              * Error in writing to file.
  401.              * Print it, skip to next file in archive.
  402.              */
  403.             if(check<0)
  404.                 msg_perror("couldn't write to file %s",skipcrud+current_filename);
  405.             else
  406.                 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+current_filename);
  407.             skip_file((long)(size - written));
  408.             break;    /* Still do the close, mod time, chmod, etc */
  409.         }
  410.  
  411.         if(f_multivol)
  412.             save_name = 0;
  413.  
  414.             /* If writing to stdout, don't try to do anything
  415.                to the filename; it doesn't exist, or we don't
  416.                want to touch it anyway */
  417.         if(f_exstdout)
  418.             break;
  419.             
  420. /*        if (gnu_extended_header(head)) {
  421.             register union record *exhdr;
  422.             register int i;
  423.  
  424.             for (i = 0; i < 21; i++) {
  425.                 long offset;
  426.  
  427.                 if (!exhdr->ext_hdr.sp[i].numbytes)
  428.                     break;
  429.                 offset = from_oct(1+12,
  430.                         exhdr->ext_hdr.sp[i].offset);
  431.                 written = from_oct(1+12,
  432.                         exhdr->ext_hdr.sp[i].numbytes);
  433.                 lseek(fd, offset, 0);
  434.                 check = write(fd, data, written);
  435.                 if (check == written) continue;
  436.  
  437.             }
  438.  
  439.  
  440.         }*/
  441.         check = close(fd);
  442.         if (check < 0) {
  443.             msg_perror("Error while closing %s",skipcrud+current_filename);
  444.         }
  445.  
  446.  
  447.     set_filestat:
  448.  
  449.         /*
  450.          * If we are root, set the owner and group of the extracted
  451.          * file.  This does what is wanted both on real Unix and on
  452.          * System V.  If we are running as a user, we extract as that
  453.          * user; if running as root, we extract as the original owner.
  454.          */
  455.         if (we_are_root) {
  456.             if (chown(skipcrud+current_filename, hstat.st_uid,
  457.                   hstat.st_gid) < 0) {
  458.                 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+current_filename,hstat.st_uid,hstat.st_gid);
  459.             }
  460.         }
  461.  
  462.         /*
  463.          * If '-k' is not set, open() or creat() could have saved
  464.          * the permission bits from a previously created file,
  465.          * ignoring the ones we specified.
  466.          * Even if -k is set, if the file has abnormal
  467.          * mode bits, we must chmod since writing or chown() has
  468.          * probably reset them.
  469.          *
  470.          * If -k is set, we know *we* created this file, so the mode
  471.          * bits were set by our open().   If the file is "normal", we
  472.          * skip the chmod.  This works because we did umask(0) if -p
  473.          * is set, so umask will have left the specified mode alone.
  474.          */
  475.         if ((!f_keep)
  476.             || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
  477.             if (chmod(skipcrud+current_filename,
  478.                   notumask & (int)hstat.st_mode) < 0) {
  479.                 msg_perror("cannot change mode of file %s to %ld",skipcrud+current_filename,notumask & (int)hstat.st_mode);
  480.             }
  481.         }
  482.         /*
  483.          * Set the modified time of the file.
  484.          * 
  485.          * Note that we set the accessed time to "now", which
  486.          * is really "the time we started extracting files".
  487.          * unless f_gnudump is used, in which case .st_atime is used
  488.          */
  489.         if (!f_modified) {
  490.             /* fixme if f_gnudump should set ctime too, but how? */
  491.             if(f_gnudump) acc_upd_times[0]=hstat.st_atime;
  492.             else acc_upd_times[0] = now;             /* Accessed now */
  493.             acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
  494.             if (utime(skipcrud+current_filename, acc_upd_times) < 0) {
  495.                 msg_perror("couldn't change access and modification times of %s",skipcrud+current_filename);
  496.             }
  497.         }
  498.  
  499.     quit:
  500.         break;
  501.  
  502.     case LF_LINK:
  503.     again_link:
  504.         check = link (current_linkname, skipcrud+current_filename);
  505.         if (check == 0)
  506.             break;
  507.         if (make_dirs(skipcrud+current_filename))
  508.             goto again_link;
  509.         if(f_gnudump && errno==EEXIST)
  510.             break;
  511.         msg_perror("Could not link %s to %s",
  512.             skipcrud+current_filename,current_linkname);
  513.         break;
  514.  
  515. #ifdef S_IFLNK
  516.     case LF_SYMLINK:
  517.     again_symlink:
  518.         check = symlink(current_linkname,
  519.                     skipcrud+current_filename);
  520.         /* FIXME, don't worry uid, gid, etc... */
  521.         if (check == 0)
  522.             break;
  523.         if (make_dirs(skipcrud+current_filename))
  524.             goto again_symlink;
  525.         msg_perror("Could not create symlink to %s",current_linkname);
  526.         break;
  527. #endif
  528.  
  529. #ifdef S_IFCHR
  530.     case LF_CHR:
  531.         hstat.st_mode |= S_IFCHR;
  532.         goto make_node;
  533. #endif
  534.  
  535. #ifdef S_IFBLK
  536.     case LF_BLK:
  537.         hstat.st_mode |= S_IFBLK;
  538.         goto make_node;
  539. #endif
  540.  
  541. #ifdef S_IFIFO
  542.     /* If local system doesn't support FIFOs, use default case */
  543.         case LF_FIFO:
  544. #ifdef sprite
  545.     again_fifo:
  546.         check = SpriteMakeNamedPipe(current_filename, &hstat);
  547.         if (check != 0) {
  548.             if (make_dirs(skipcrud+current_filename)) {
  549.             goto again_fifo;
  550.             }
  551.             msg_perror("Could not make named pipe %s",
  552.             skipcrud+current_filename);
  553.             break;
  554.         }
  555.         goto set_filestat;
  556. #else
  557.         hstat.st_mode |= S_IFIFO;
  558.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  559.         goto make_node;
  560. #endif /* sprite */
  561. #endif /* S_IFIFO */
  562.  
  563. #ifdef sprite
  564.     case LF_PSEUDODEV:
  565.     again_pdev:
  566.         check = SpriteMakePseudoDev(current_filename, &hstat);
  567.         if (check != 0) {
  568.             if (make_dirs(skipcrud+current_filename)) {
  569.             goto again_pdev;
  570.             }
  571.             msg_perror("Could not make pseudo device %s",
  572.             skipcrud+current_filename);
  573.             break;
  574.         }
  575.         goto set_filestat;
  576.  
  577.     case LF_RMTLINK:
  578.     again_rmtlink:
  579.         check = SpriteMakeRemoteLink(current_linkname,
  580.                          current_filename);
  581.         if (check != 0) {
  582.             if (make_dirs(skipcrud+current_filename)) {
  583.             goto again_rmtlink;
  584.             }
  585.             msg_perror("Could not create remote link %s", current_linkname);
  586.             break;
  587.         }
  588.         goto set_filestat;
  589.  
  590. #endif /* sprite */
  591.  
  592.     make_node:
  593.         check = mknod(skipcrud+current_filename,
  594.                   (int) hstat.st_mode, (int) hstat.st_rdev);
  595.         if (check != 0) {
  596.             if (make_dirs(skipcrud+current_filename))
  597.                 goto make_node;
  598.             msg_perror("Could not make %s",skipcrud+current_filename);
  599.             break;
  600.         };
  601.         goto set_filestat;
  602.  
  603.     case LF_DIR:
  604.     case LF_DUMPDIR:
  605.         namelen = strlen(skipcrud+current_filename)-1;
  606.     really_dir:
  607.         /* Check for trailing /, and zap as many as we find. */
  608.         while (namelen && current_filename[skipcrud+namelen] == '/')
  609.             current_filename[skipcrud+namelen--] = '\0';
  610.         if(f_gnudump) {        /* Read the entry and delete files
  611.                        that aren't listed in the archive */
  612.             gnu_restore(skipcrud+current_filename);
  613.  
  614.         } else if(head->header.linkflag==LF_DUMPDIR)
  615.             skip_file((long)(hstat.st_size));
  616.  
  617.  
  618.     again_dir:
  619.         check = mkdir(skipcrud+current_filename,
  620.                   0300 | (int)hstat.st_mode);
  621.         if (check != 0) {
  622. #ifdef ALLOW_NO_RECURSE
  623.                 if (f_no_recurse) {
  624.                 if (errno == ENOTDIR || errno == EEXIST) {
  625.                 /* check and see if it is a regular file. */
  626.                 struct stat buf;
  627.  
  628.                 if (stat(skipcrud+current_filename, &buf) != 0) {
  629.                     msg_perror("Could not stat %s",
  630.                     skipcrud+current_filename);
  631.                     break;
  632.                 }
  633.                 switch (buf.st_mode & S_IFMT) {
  634.  
  635.                 case S_IFDIR:
  636.                     break;
  637.  
  638.                 case S_IFREG:
  639.                     msg("Unlinking %s", skipcrud+current_filename);
  640.                     if (unlink(skipcrud+current_filename) == 0) {
  641.                     goto again_dir;
  642.                     }
  643.                     msg_perror("Could not unlink %s",
  644.                     skipcrud+current_filename);
  645.                     break;
  646.  
  647.                 default:
  648.                     msg("%s already exists");
  649.                     break;
  650.                 }
  651.                 break;
  652.                 }
  653.             }
  654. #endif
  655.             if (make_dirs(skipcrud+current_filename))
  656.                 goto again_dir;
  657.             /* If we're trying to create '.', let it be. */
  658.             if (current_filename[skipcrud+namelen] == '.' && 
  659.                 (namelen==0 ||
  660.                  current_filename[skipcrud+namelen-1]=='/'))
  661.                 goto check_perms;
  662.             if(f_gnudump && errno==EEXIST)
  663.                 break;
  664.             msg_perror("Could not make directory %s",skipcrud+current_filename);
  665.             break;
  666.         }
  667.  
  668.     check_perms:
  669.         if (0300 != (0300 & (int) hstat.st_mode)) {
  670.             hstat.st_mode |= 0300;
  671.             msg("Added write and execute permission to directory %s",
  672.               skipcrud+current_filename);
  673.         }
  674.  
  675.         goto set_filestat;
  676.         /* FIXME, Remember timestamps for after files created? */
  677.         /* FIXME, change mode after files created (if was R/O dir) */
  678.     case LF_VOLHDR:
  679.         if(f_verbose) {
  680.             printf("Reading %s\n",current_filename);
  681.         }
  682.         break;
  683.  
  684.     case LF_MULTIVOL:
  685.         msg("Can't extract '%s'--file is continued from another volume\n",current_filename);
  686.         skip_file((long)hstat.st_size);
  687.         break;
  688.  
  689.     }
  690.  
  691.     return;
  692. }
  693.  
  694. /*
  695.  * After a file/link/symlink/dir creation has failed, see if
  696.  * it's because some required directory was not present, and if
  697.  * so, create all required dirs.
  698.  */
  699. int
  700. make_dirs(pathname)
  701.     char *pathname;
  702. {
  703.     char *p;            /* Points into path */
  704.     int madeone = 0;        /* Did we do anything yet? */
  705.     int save_errno = errno;        /* Remember caller's errno */
  706.     int check;
  707.  
  708.     if (errno != ENOENT)
  709.         return 0;        /* Not our problem */
  710.  
  711.     for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
  712.         /* Avoid mkdir of empty string, if leading or double '/' */
  713.         if (p == pathname || p[-1] == '/')
  714.             continue;
  715.         /* Avoid mkdir where last part of path is '.' */
  716.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  717.             continue;
  718.         *p = 0;                /* Truncate the path there */
  719. again_dir:        
  720.         check = mkdir (pathname, 0777);    /* Try to create it as a dir */
  721.         if (check == 0) {
  722. #ifdef ALLOW_NO_RECURSE
  723.             if (f_no_recurse && errno == ENOTDIR) {
  724.             /* check and see if it is a regular file. */
  725.             struct stat buf;
  726.  
  727.             if (stat(pathname, &buf) != 0) {
  728.                 msg_perror("Could not stat %s", pathname);
  729.             } else if ((buf.st_mode & S_IFMT) == S_IFREG) {
  730.                 msg("Unlinking %s", pathname);
  731.                 if (unlink(pathname) == 0) {
  732.                 goto again_dir;
  733.                 }
  734.                 msg_perror("Could not unlink %s", pathname);
  735.             }
  736.             }
  737. #endif
  738.             /* Fix ownership */
  739.             if (we_are_root) {
  740.             if (chown(pathname, hstat.st_uid,
  741.                 hstat.st_gid) < 0) {
  742.                 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
  743.                 }
  744.             }
  745.             pr_mkdir(pathname, p-pathname, notumask&0777);
  746.             madeone++;        /* Remember if we made one */
  747.             *p = '/';
  748.             continue;
  749.         }
  750.         *p = '/';
  751.         if (errno == EEXIST)        /* Directory already exists */
  752.             continue;
  753.         /*
  754.          * Some other error in the mkdir.  We return to the caller.
  755.          */
  756.         break;
  757.     }
  758.  
  759.     errno = save_errno;        /* Restore caller's errno */
  760.     return madeone;            /* Tell them to retry if we made one */
  761. }
  762.  
  763. extract_sparse_file(fd, sizeleft, totalsize, name)
  764.     int    fd;
  765.     long    *sizeleft,
  766.         totalsize;
  767.     char    *name;
  768. {        
  769.     register char    *data;
  770.     union record    *datarec;
  771.     int    sparse_ind = 0;
  772.     int    written,
  773.         count;
  774.  
  775.     /* assuming sizeleft is initially totalsize */
  776.  
  777.  
  778.     while (*sizeleft > 0) {
  779.         datarec = findrec();
  780.         if (datarec == NULL) {
  781.             msg("Unexpected EOF on archive file");
  782.             return;
  783.         }
  784.         lseek(fd, sparsearray[sparse_ind].offset, 0);
  785.         written = sparsearray[sparse_ind++].numbytes;
  786.         while (written > RECORDSIZE) {
  787.             count = write(fd, datarec->charptr, RECORDSIZE);
  788.             if (count < 0) 
  789.                 msg_perror("couldn't write to file %s", name);
  790.             written -= count;
  791.             *sizeleft -= count;
  792.             userec(datarec);
  793.             datarec = findrec();
  794.         }
  795.  
  796.         count = write(fd, datarec->charptr, written);
  797.  
  798.         if (count < 0) {
  799.             msg_perror("couldn't write to file %s", name);
  800.         } else if (count != written) {
  801.             msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
  802.             skip_file((long) (*sizeleft));
  803.         }
  804.  
  805.         written -= count;
  806.         *sizeleft -= count;        
  807.         userec(datarec);
  808.     
  809.     }
  810. /*    if (end_nulls) {
  811.         register int i;
  812.  
  813.         printf("%d\n", (int) end_nulls);
  814.         for (i = 0; i < end_nulls; i++)
  815.             write(fd, "\000", 1);
  816.     }*/
  817.     userec(datarec);
  818. }
  819.